package com.ssy.lingxi.settle.accounts.serviceimpl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.ssy.lingxi.common.constant.order.OrderPayTypeEnum;
import com.ssy.lingxi.common.constant.order.OrderPaymentSettlementStatusEnum;
import com.ssy.lingxi.common.constant.settle.ReceiptInvoiceOrderTypeEnum;
import com.ssy.lingxi.common.constant.settle.SettlementOrderTypeEnum;
import com.ssy.lingxi.common.constant.settle.SettlementTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.component.rabbitMQ.service.IRabbitMQUtils;
import com.ssy.lingxi.dto.model.constant.SettleAccountsConstant;
import com.ssy.lingxi.dto.request.PlatformCommunicationPayVO;
import com.ssy.lingxi.dto.request.PlatformSettlementOrderPaymentVO;
import com.ssy.lingxi.dto.response.PlatformSettlementAllInPayVO;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.order.api.model.vo.request.MemberSettleChannelQueryVO;
import com.ssy.lingxi.order.api.model.vo.response.MemberSettleChannelVO;
import com.ssy.lingxi.order.api.model.vo.response.PlatformSettlementTypeVO;
import com.ssy.lingxi.pay.api.dto.request.eAccount.PlatFormRePayRequest;
import com.ssy.lingxi.pay.api.dto.request.eAccount.ReceivePaymentRequest;
import com.ssy.lingxi.pay.api.model.vo.response.allInPay.SignalAgentPayRespVO;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.report.api.enums.SettleAccountPlatformOperateTypeEnum;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import com.ssy.lingxi.settle.accounts.entity.PlatformSettlementDO;
import com.ssy.lingxi.settle.accounts.entity.PlatformSettlementDetailDO;
import com.ssy.lingxi.settle.accounts.model.bo.PayProveBO;
import com.ssy.lingxi.settle.accounts.model.constant.CommonBooleanEnum;
import com.ssy.lingxi.settle.accounts.model.constant.PlatformSettlementExcelEnum;
import com.ssy.lingxi.settle.accounts.model.constant.SettlementStatusEnum;
import com.ssy.lingxi.settle.accounts.model.constant.SettlementWayEnum;
import com.ssy.lingxi.settle.accounts.model.vo.request.*;
import com.ssy.lingxi.settle.accounts.model.vo.response.CommunicationPayProveVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.PagePlatformSettlementDetailVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.PlatformSettlementDetailVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.PlatformSettlementVO;
import com.ssy.lingxi.settle.accounts.repository.PlatformSettlementDetailRepository;
import com.ssy.lingxi.settle.accounts.repository.PlatformSettlementRepository;
import com.ssy.lingxi.settle.accounts.service.IFeignService;
import com.ssy.lingxi.settle.accounts.service.IPlatformSettlementService;
import com.ssy.lingxi.settle.accounts.utils.OrderDateTimeUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 平台结算接口实现
 * @author 伍将
 * @date 2020/10/29
 * @version 2.0.0
 */
@Service
public class PlatformSettlementServiceImpl implements IPlatformSettlementService {

    @Resource
    private PlatformSettlementRepository repository;

    @Resource
    private PlatformSettlementDetailRepository detailRepository;

    @Resource
    private IFeignService feignService;

    @Resource
    private IRabbitMQUtils rabbitMQUtils;

    /**
     * 分页查询应收账款结算
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser: 
     * @param pageVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformSettlementVO>>
     **/
    @Override
    public Wrapper<PageData<PlatformSettlementVO>> pageReceivableSettlement(UserLoginCacheDTO sysUser, PlatformSettlementPageVO pageVO) {
        return pageSettlement(sysUser, pageVO, false);
    }

    /**
     * 确认对账完成
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param completeVO:
     * @return com.ssy.lingxi.common.response.Wrapper
     **/
    @Override
    public Wrapper<Void> confirmAccountComplete(UserLoginCacheDTO sysUser, ConfirmAccountCompleteVO completeVO) {
        PlatformSettlementDO entity = repository.findById(completeVO.getSettlementId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        if (!entity.getStatus().equals(SettlementStatusEnum.TO_BE_ACCOUNT_COMPLETE.getCode())) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NO_CONFIRM_ACCOUNT_COMPLETE);
        }
        entity.setStatus(SettlementStatusEnum.TO_BE_PAY.getCode());
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增操作通知
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        // 支付方待对账-1，待付款+1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(0L);
        noticeVO.setRoleId(0L);
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_ACCOUNTS.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        // 收款方待对账-1，待付款+1
        noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(entity.getMemberId());
        noticeVO.setRoleId(entity.getRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_ACCOUNTS.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        feignService.addSystemOperateNoticeList(noticeVOList);

        // 新增系统通知
        List<SystemMessageRequest> requestList = new ArrayList<>();
        List<String> params = new ArrayList<>();
        params.add(entity.getSettlementNo());
        SystemMessageRequest request = new SystemMessageRequest();
        request.setMemberId(0L);
        request.setRoleId(0L);
        request.setMessageNotice(MessageTemplateCode.agency_receipt_upload_bill);
        request.setParams(params);
        requestList.add(request);
        request = new SystemMessageRequest();
        request.setMemberId(entity.getMemberId());
        request.setRoleId(entity.getRoleId());
        request.setMessageNotice(MessageTemplateCode.agency_receipt_upload_bill);
        request.setParams(params);
        requestList.add(request);
        feignService.batchSendSystemMessage(requestList);

        return Wrapper.success();
    }

    /**
     * 确认付款凭证
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param confirmVO:
     * @return com.ssy.lingxi.common.response.Wrapper
     **/
    @Override
    public Wrapper<Void> confirmPayProve(UserLoginCacheDTO sysUser, ConfirmPayProve confirmVO) {
        PlatformSettlementDO entity = repository.findById(confirmVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        if (!entity.getStatus().equals(SettlementStatusEnum.TO_BE_RECEIPT.getCode())) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NO_CONFIRM_PAY_PROVE);
        }
        if (confirmVO.getStatus().equals(CommonBooleanEnum.YES.getCode())) {
            entity.setStatus(SettlementStatusEnum.COMPLETE.getCode());
        } else {
            entity.setStatus(SettlementStatusEnum.TO_BE_PAY.getCode());
        }
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增操作通知
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        // 支付方待收款-1，已完成/待付款+1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(0L);
        noticeVO.setRoleId(0L);
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setReduceCount(1L);
        if (SettlementStatusEnum.COMPLETE.getCode().equals(entity.getStatus())) {
            noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.COMPLETE.getCode());
        } else if (SettlementStatusEnum.TO_BE_PAY.getCode().equals(entity.getStatus())) {
            noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_PAY.getCode());
        }
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        // 收款方待收款-1，已完成/待付款+1
        noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(entity.getMemberId());
        noticeVO.setRoleId(entity.getRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setReduceCount(1L);
        if (SettlementStatusEnum.COMPLETE.getCode().equals(entity.getStatus())) {
            noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.COMPLETE.getCode());
        } else if (SettlementStatusEnum.TO_BE_PAY.getCode().equals(entity.getStatus())) {
            noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_PAY.getCode());
        }
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        feignService.addSystemOperateNoticeList(noticeVOList);

        // 新增系统通知
        if (SettlementStatusEnum.TO_BE_PAY.getCode().equals(entity.getStatus())) {
            List<SystemMessageRequest> requestList = new ArrayList<>();
            List<String> params = new ArrayList<>();
            params.add(entity.getSettlementNo());
            SystemMessageRequest request = new SystemMessageRequest();
            request.setMemberId(0L);
            request.setRoleId(0L);
            request.setMessageNotice(MessageTemplateCode.agency_receipt_upload_bill);
            request.setParams(params);
            requestList.add(request);
            request = new SystemMessageRequest();
            request.setMemberId(entity.getMemberId());
            request.setRoleId(entity.getRoleId());
            request.setMessageNotice(MessageTemplateCode.agency_receipt_upload_bill);
            request.setParams(params);
            requestList.add(request);
            feignService.batchSendSystemMessage(requestList);
        }

        return Wrapper.success();
    }

    /**
     * 收款方查看凭证
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<java.util.List < com.ssy.lingxi.settle.accounts.mode.bo.PayProveBO>>
     **/
    @Override
    public Wrapper<List<PayProveBO>> getReceivablePayProve(UserLoginCacheDTO sysUser, Long id) {
        return getPayProve(sysUser, id);
    }

    /**
     * 获取应收款账款结算详情
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformSettlementDetailVO>
     **/
    @Override
    public Wrapper<PlatformSettlementDetailVO> getReceivableDetail(UserLoginCacheDTO sysUser, Long id) {
        return getDetail(sysUser, id);
    }

    /**
     * 分页查询应收款账款结算详情
     * @author 伍将
     * @date 2020/10/30
     * @param sysUser:
     * @param pageVO:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PagePlatformSettlementDetailVO>>
     **/
    @Override
    public Wrapper<PageData<PagePlatformSettlementDetailVO>> pageReceivableSettlementDetail(UserLoginCacheDTO sysUser, PlatformSettlementDetailPageVO pageVO) {
        return pageSettlementDetail(sysUser, pageVO, false);
    }

    /**
     * 分页查询应付账款结算
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser: 
     * @param pageVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformSettlementVO>>
     **/
    @Override
    public Wrapper<PageData<PlatformSettlementVO>> pagePayableSettlement(UserLoginCacheDTO sysUser, PlatformSettlementPageVO pageVO) {
        return pageSettlement(sysUser, pageVO, true);
    }

    /**
     * 支付
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param payVO:
     * @return com.ssy.lingxi.common.response.Wrapper
     **/
    @Override
    public Wrapper<Void> pay(UserLoginCacheDTO sysUser, PayVO payVO) {
        PlatformSettlementDO entity = repository.findById(payVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        if (!entity.getStatus().equals(SettlementStatusEnum.TO_BE_PAY.getCode())) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NO_PAY);
        }
        entity.setPayProveList(payVO.getProveList());
        entity.setStatus(SettlementStatusEnum.TO_BE_RECEIPT.getCode());
        entity.setUpdateTime(System.currentTimeMillis());
        entity.setPayTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增操作通知
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        // 支付方待付款-1，待收款+1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(0L);
        noticeVO.setRoleId(0L);
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        // 收款方待付款-1，待收款+1
        noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(entity.getMemberId());
        noticeVO.setRoleId(entity.getRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        feignService.addSystemOperateNoticeList(noticeVOList);

        // 新增系统通知
        List<SystemMessageRequest> requestList = new ArrayList<>();
        List<String> params = new ArrayList<>();
        params.add(entity.getSettlementNo());
        SystemMessageRequest request = new SystemMessageRequest();
        request.setMemberId(0L);
        request.setRoleId(0L);
        request.setMessageNotice(MessageTemplateCode.agency_receipt_gathering);
        request.setParams(params);
        requestList.add(request);
        request = new SystemMessageRequest();
        request.setMemberId(entity.getMemberId());
        request.setRoleId(entity.getRoleId());
        request.setMessageNotice(MessageTemplateCode.agency_receipt_gathering);
        request.setParams(params);
        requestList.add(request);
        feignService.batchSendSystemMessage(requestList);

        return Wrapper.success();
    }

    /**
     * 付款方查看凭证
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<java.util.List < com.ssy.lingxi.settle.accounts.mode.bo.PayProveBO>>
     **/
    @Override
    public Wrapper<List<PayProveBO>> getPayablePayProve(UserLoginCacheDTO sysUser, Long id) {
        return getPayProve(sysUser, id);
    }

    /**
     * 获取应付账款结算详情
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformSettlementDetailVO>
     **/
    @Override
    public Wrapper<PlatformSettlementDetailVO> getPayableDetail(UserLoginCacheDTO sysUser, Long id) {
        return getDetail(sysUser, id);
    }

    /**
     * 获取应付账款结算详情
     * @author 伍将
     * @date 2020/10/30
     * @param sysUser:
     * @param pageVO:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PagePlatformSettlementDetailVO>>
     **/
    @Override
    public Wrapper<PageData<PagePlatformSettlementDetailVO>> pagePayableSettlementDetail(UserLoginCacheDTO sysUser, PlatformSettlementDetailPageVO pageVO) {
        return pageSettlementDetail(sysUser, pageVO, true);
    }

    /**
     * 分页查询平台结算
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param pageVO:
     * @param isSettlement:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformSettlementVO>>
     **/
    private Wrapper<PageData<PlatformSettlementVO>> pageSettlement(UserLoginCacheDTO sysUser, PlatformSettlementPageVO pageVO, Boolean isSettlement) {
        // step 1: 组装查询条件
        Specification<PlatformSettlementDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (!pageVO.getStatus().equals(SettlementStatusEnum.ALL.getCode())) {
                list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), pageVO.getStatus()));
            }
            if (StringUtils.hasLength(pageVO.getStartTime())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("settlementDate").as(Long.class), DateUtil.parse(pageVO.getStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getEndTime())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("settlementDate").as(Long.class), DateUtil.parse(pageVO.getEndTime()).getTime()));
            }
            if (isSettlement) {
                if (StringUtils.hasLength(pageVO.getSettlementName())) {
                    list.add(criteriaBuilder.like(root.get("settlementName").as(String.class), "%" + pageVO.getSettlementName().trim() + "%"));
                }
            } else {
                list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), sysUser.getMemberId()));
                list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), sysUser.getMemberRoleId()));
            }
            if (StringUtils.hasLength(pageVO.getSettlementNo())) {
                list.add(criteriaBuilder.like(root.get("settlementNo").as(String.class), "%" + pageVO.getSettlementNo().trim() + "%"));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());

        // step 3: 分页查询数据
        Page<PlatformSettlementDO> result = repository.findAll(spec, page);

        // step 4: 组装返回数据
        List<PlatformSettlementVO> resultList = result.getContent().stream().map(r -> {
            PlatformSettlementVO queryVO = new PlatformSettlementVO();
            queryVO.setId(r.getId());
            queryVO.setSettlementNo(r.getSettlementNo());
            queryVO.setSettlementDate(DateUtil.format(DateUtil.date(r.getSettlementDate()), "yyyy-MM-dd"));
            // 预计付款日期
            queryVO.setEstimatedPaymentDate(DateUtil.format(DateUtil.date(r.getEstimatedPaymentDate()), "yyyy-MM-dd"));
            // 实际付款日期
            queryVO.setPayTime(Optional.ofNullable(r.getPayTime()).filter(f -> f.compareTo(0L)>0).map(map ->DateUtil.format(DateUtil.date(map), "yyyy-MM-dd HH:mm:ss")).orElse(""));
            queryVO.setSettlementWayName(SettlementWayEnum.getMessage(r.getSettlementWay()));
            queryVO.setSettlementName(r.getSettlementName());
            queryVO.setTotalCount(r.getTotalCount());
            queryVO.setCollectAmount(BigDecimal.valueOf(r.getCollectAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
            queryVO.setBrokerage(BigDecimal.valueOf(r.getBrokerage()).setScale(2, RoundingMode.HALF_UP).doubleValue());
            queryVO.setAmount(BigDecimal.valueOf(r.getAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
            queryVO.setSettlementTime(DateUtil.format(DateUtil.date(r.getSettlementTime()), "yyyy-MM-dd HH:mm"));
            queryVO.setStatus(r.getStatus());
            queryVO.setStatusName(SettlementStatusEnum.getMessage(r.getStatus()));
            queryVO.setPayWay(r.getPayWay());
            queryVO.setPayWayName(SettlementTypeEnum.getName(r.getPayWay()));
            queryVO.setMemberId(r.getMemberId());
            queryVO.setRoleId(r.getRoleId());

            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 获取支付凭证
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<java.util.List < com.ssy.lingxi.settle.accounts.mode.bo.PayProveBO>>
     **/
    private Wrapper<List<PayProveBO>> getPayProve(UserLoginCacheDTO sysUser, Long id) {

        PlatformSettlementDO entity = repository.findById(id).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }

        return Wrapper.success(entity.getPayProveList());
    }

    /**
     * 获取会员结算详情
     * @author 伍将
     * @date 2020/10/29
     * @param sysUser:
     * @param id:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformSettlementDetailVO>
     **/
    private Wrapper<PlatformSettlementDetailVO> getDetail(UserLoginCacheDTO sysUser, Long id) {
        PlatformSettlementDO entity = repository.findById(id).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }

        PlatformSettlementDetailVO result = new PlatformSettlementDetailVO();
        result.setId(entity.getId());
        result.setSettlementNo(entity.getSettlementNo());
        result.setSettlementWayName(SettlementWayEnum.getMessage(entity.getSettlementWay()));
        result.setTotalCount(entity.getTotalCount());
        result.setAmount(entity.getAmount());
        result.setSettlementDate(DateUtil.format(DateUtil.date(entity.getSettlementDate()), "yyyy-MM-dd"));
        result.setEstimatedPaymentDate(DateUtil.format(DateUtil.date(entity.getEstimatedPaymentDate()), "yyyy-MM-dd"));
        result.setStatusName(SettlementStatusEnum.getMessage(entity.getStatus()));

        return Wrapper.success(result);
    }

    /**
     * 分页查询结算明细
     * @author 伍将
     * @date 2020/10/30
     * @param sysUser:
     * @param pageVO:
     * @param isSettlement:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PagePlatformSettlementDetailVO>>
     **/
    public Wrapper<PageData<PagePlatformSettlementDetailVO>> pageSettlementDetail(UserLoginCacheDTO sysUser, PlatformSettlementDetailPageVO pageVO, Boolean isSettlement) {
        // step 1: 组装查询条件
        Specification<PlatformSettlementDetailDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("settlementId").as(Long.class), pageVO.getSettlementId()));
            if (!isSettlement) {
                list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), sysUser.getMemberId()));
            }
            if (StringUtils.hasLength(pageVO.getOrderStartTime())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("orderTime").as(Long.class), DateUtil.parse(pageVO.getOrderStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getOrderEndTime())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("orderTime").as(Long.class),DateUtil.endOfDay(DateUtil.parse(pageVO.getOrderEndTime())).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getPayStartTime())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("payTime").as(Long.class), DateUtil.parse(pageVO.getPayStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getPayEndTime())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("payTime").as(Long.class), DateUtil.endOfDay(DateUtil.parse(pageVO.getPayEndTime())).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getOrderNo())) {
                list.add(criteriaBuilder.like(root.get("orderNo").as(String.class), "%" + pageVO.getOrderNo().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getOrderAbstract())) {
                list.add(criteriaBuilder.like(root.get("orderAbstract").as(String.class), "%" + pageVO.getOrderAbstract().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("orderTime").descending());

        // step 3: 分页查询数据
        Page<PlatformSettlementDetailDO> result = detailRepository.findAll(spec, page);

        // step 4: 组装返回数据
        List<PagePlatformSettlementDetailVO> resultList = result.getContent().stream().map(r -> {
            PagePlatformSettlementDetailVO queryVO = new PagePlatformSettlementDetailVO();
            queryVO.setOrderNo(r.getOrderNo());
            queryVO.setOrderAbstract(r.getOrderAbstract());
            queryVO.setSettlementOrderTypeName(SettlementOrderTypeEnum.getMessage(r.getSettlementOrderType(), ""));
            queryVO.setOrderTime(DateUtil.format(DateUtil.date(r.getOrderTime()), "yyyy-MM-dd"));
            queryVO.setOrderTypeName(ReceiptInvoiceOrderTypeEnum.getMessage(r.getOrderType()));
            queryVO.setOrderAmount(BigDecimal.valueOf(r.getOrderAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
            queryVO.setCollectAmount(BigDecimal.valueOf(r.getCollectAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
            queryVO.setBrokerage(BigDecimal.valueOf(r.getBrokerage()).setScale(2, RoundingMode.HALF_UP).doubleValue());
            queryVO.setPayTime(DateUtil.format(DateUtil.date(r.getPayTime()), "yyyy-MM-dd HH:mm"));
            queryVO.setRatio(r.getRatio());
            queryVO.setSettlementAmount(BigDecimal.valueOf(r.getSettlementAmount()).setScale(2, RoundingMode.HALF_UP).doubleValue());
            queryVO.setIsHasTaxName(CommonBooleanEnum.getMessage(r.getIsHasTax()));
            queryVO.setTaxRate(r.getTaxRate());
            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 是否存在佣金
     * @author 伍将
     * @date 2021/1/21
     * @return Boolean
     **/
    @Override
    public Wrapper<Boolean> isExistsBrokerage() {
        return Wrapper.success(detailRepository.existsByBrokerageGreaterThan(0D));
    }

    /**
     *
     * 平台代收账款结算-通联支付付款
     * @author 彭冬冬
     * @date 2021/11/29
     * @param sysUser 登录用户
     * @param communicationPayVO 联通支付付款VO
     * @return 支付结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Wrapper<Void> communicationPay(UserLoginCacheDTO sysUser, PlatformCommunicationPayVO communicationPayVO) {
        // 1.校验
        PlatformSettlementDO entity = repository.findById(communicationPayVO.getId()).orElse(null);
        if (Objects.isNull(entity)) {
            return Wrapper.fail(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        // 2.获取结算明细
        Specification<PlatformSettlementDetailDO> spec = (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("settlementId").as(Long.class), communicationPayVO.getId());
        List<PlatformSettlementDetailDO> details = detailRepository.findAll(spec);
        List<String> orderNos = details.stream().map(PlatformSettlementDetailDO::getOrderNo).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(orderNos)) {
            return Wrapper.fail(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        // 3.保存状态
        entity.setStatus(SettlementStatusEnum.TO_BE_RECEIPT.getCode());
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);


        // 4.组装远端调用【联通支付-平台转账接口】请求参数
        PlatFormRePayRequest request = new PlatFormRePayRequest();
        request.setMemberId(entity.getMemberId()); // 会员id(收款方)
        request.setMemberRoleId(entity.getRoleId()); // 会员角色id(收款方)
        // 生成商户订单号
        String tradeNo = entity.getSettlementNo() + "-" + RandomStringUtils.random(7, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
        request.setOrderCode(tradeNo); // 商户订单号
        request.setPayMoney(entity.getAmount()); // 金额
        // 组装明细项
        // 获取订单来源的明细项
        List<PlatformSettlementDetailDO> resourceOrderDetails = details.stream().filter(f -> SettlementOrderTypeEnum.ORDER.getCode().equals(f.getSettlementOrderType())).collect(Collectors.toList());
        // 获取售后退货退款来源明细项
        List<PlatformSettlementDetailDO> resourceReturnGoodDetails = details.stream().filter(f -> SettlementOrderTypeEnum.RETURN_GOODS.getCode().equals(f.getSettlementOrderType())).collect(Collectors.toList());
        // 构建请求参数明细项
        List<ReceivePaymentRequest> receiveList = builReceiveList(resourceOrderDetails, resourceReturnGoodDetails);
        request.setReceiveList(receiveList);
        // 5.远端调用【联通支付-平台转账接口】 会员校验（需要调整），重复支付状态码需提供
        Wrapper<SignalAgentPayRespVO> payWrapper = feignService.allInPayEscrowPayment(request);
        if (payWrapper == null) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(ResponseCode.SERVICE_PAY_ERROR);
        }
        //  状态码不是成功
        if (payWrapper.getCode() != ResponseCode.SUCCESS.getCode()
                /*&& payWrapper.getCode() != AllInPayErrorCodeEnum.DUPLICATE_ORDER_NUMBER.getCode()*/) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(payWrapper.getCode(), payWrapper.getMessage());
        }

        // 6.修改状态
        entity.setStatus(SettlementStatusEnum.COMPLETE.getCode());
        // 结算时间
        entity.setSettlementDate(System.currentTimeMillis());
        entity.setUpdateTime(System.currentTimeMillis());
        entity.setPayTime(System.currentTimeMillis());
        entity.setTradeNo(tradeNo);
        repository.saveAndFlush(entity);
        // 7.新增操作通知
        List<OperateNoticeVO> noticeVOList = new ArrayList<>();
        // 7.1.支付方待付款-1，待收款+1
        OperateNoticeVO noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(0L);
        noticeVO.setRoleId(0L);
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        // 7.2.收款方待付款-1，待收款+1
        noticeVO = new OperateNoticeVO();
        noticeVO.setMemberId(entity.getMemberId());
        noticeVO.setRoleId(entity.getRoleId());
        noticeVO.setDataSource(OperateDataSourceEnum.SETTLE_ACCOUNT_PLATFORM.getCode());
        noticeVO.setReduceOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_PAY.getCode());
        noticeVO.setReduceCount(1L);
        noticeVO.setIncreaseOperateType(SettleAccountPlatformOperateTypeEnum.TO_BE_RECEIPT.getCode());
        noticeVO.setIncreaseCount(1L);
        noticeVOList.add(noticeVO);
        feignService.addSystemOperateNoticeList(noticeVOList);

        // 8.新增系统通知
        List<SystemMessageRequest> requestList = new ArrayList<>();
        List<String> params = new ArrayList<>();
        params.add(entity.getSettlementNo());
        SystemMessageRequest messageRequest = new SystemMessageRequest();
        messageRequest.setMemberId(0L);
        messageRequest.setRoleId(0L);
        messageRequest.setMessageNotice(MessageTemplateCode.agency_receipt_gathering);
        messageRequest.setParams(params);
        requestList.add(messageRequest);
        messageRequest = new SystemMessageRequest();
        messageRequest.setMemberId(entity.getMemberId());
        messageRequest.setRoleId(entity.getRoleId());
        messageRequest.setMessageNotice(MessageTemplateCode.agency_receipt_gathering);
        messageRequest.setParams(params);
        requestList.add(messageRequest);
        feignService.batchSendSystemMessage(requestList);
        // 9.推送到MQ
        List<Long> payIds = resourceOrderDetails.stream().map(PlatformSettlementDetailDO::getPaymentId).collect(Collectors.toList());
        PlatformSettlementOrderPaymentVO messageObject = new PlatformSettlementOrderPaymentVO();
        messageObject.setPaymentIds(payIds);
        messageObject.setSettlementStatus(OrderPaymentSettlementStatusEnum.SUCCESS.getCode());
        String json = JSONUtil.toJsonStr(messageObject);
        rabbitMQUtils.sendMsg(SettleAccountsConstant.SA_PLATFORM_SETTLEMENT_ALL_IN_PAY_EXCHANGE, SettleAccountsConstant.SA_PLATFORM_SETTLEMENT_ALL_IN_ROUTING_KEY,json);
        return Wrapper.success();
    }

    /**
     * 构建通联支付请求明细数据
     * @param resourceOrderDetails 来源订单的结算明细列表
     * @param resourceReturnGoodDetails 来源售后退货订单结算明细
     * @return 通联支付请求明细数据
     */
    private List<ReceivePaymentRequest> builReceiveList(List<PlatformSettlementDetailDO> resourceOrderDetails, List<PlatformSettlementDetailDO> resourceReturnGoodDetails) {
        // 来源订单的结算明细列表 必须有数据
        if (CollectionUtils.isEmpty(resourceOrderDetails)) {
            throw new BusinessException(ResponseCode.ACCOUNTS_PAYABLE_SETTLEMENT_ORDER_PAYMENT_EXIT);
        }
        // 场景1 - 本次结算没有 来源售后退货订单结算明细
        if (CollectionUtils.isEmpty(resourceReturnGoodDetails)) {
            return resourceOrderDetails.stream().map(map -> {
                ReceivePaymentRequest receivePaymentRequest = new ReceivePaymentRequest();
                receivePaymentRequest.setBizOrderNo(map.getPaymentTradeNo());
                receivePaymentRequest.setPayMoney(map.getSettlementAmount());
                return receivePaymentRequest;
            }).collect(Collectors.toList());
        }
        // 场景2 - 有来源源售后退货订单结算明细 但是和来源订单的结算明细列表没有匹配
        // 获取来源订单的结算明细列表 支付id set
        Set<Long> paymentIdSet = resourceOrderDetails.stream().map(PlatformSettlementDetailDO::getPaymentId).collect(Collectors.toSet());
        resourceReturnGoodDetails.forEach( e -> {
            if (!paymentIdSet.contains(e.getPaymentId())) {
                throw new BusinessException(ResponseCode.ACCOUNTS_PAYABLE_SETTLEMENT_RETURN_GOODS_NOT_MATCH_ORDER);
            }
        });
        // 场景3 - 有来源源售后退货订单结算明细和来源订单结算明细都有匹配
        return resourceOrderDetails.stream().map(map -> {
            ReceivePaymentRequest receivePaymentRequest = new ReceivePaymentRequest();
            receivePaymentRequest.setBizOrderNo(map.getPaymentTradeNo());
            BigDecimal reduce = resourceReturnGoodDetails.stream()
                    .filter(f -> map.getPaymentId().equals(f.getPaymentId()))
                    .map(item -> BigDecimal.valueOf(item.getSettlementAmount()).setScale(2, RoundingMode.HALF_UP))
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP);

            Double payMoney = BigDecimal.valueOf(map.getSettlementAmount()).add(reduce).setScale(2, RoundingMode.HALF_UP).doubleValue();
            receivePaymentRequest.setPayMoney(payMoney);
            return receivePaymentRequest;
        }).filter(f ->
                BigDecimal.valueOf(f.getPayMoney()).setScale(2, RoundingMode.HALF_UP)
                        .compareTo(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)) > 0).collect(Collectors.toList());
    }

    /**
     * @author 彭冬冬
     * @date 2021/11/29
     * @param sysUser 登录用户
     * @param id 结算单号id
     * @return 平台结算
     */
    @Override
    public Wrapper<CommunicationPayProveVO> getCommunicationPayProve(UserLoginCacheDTO sysUser, Long id) {
        PlatformSettlementDO entity = repository.findById(id).orElse(null);
        if (Objects.isNull(entity)) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        CommunicationPayProveVO data = new CommunicationPayProveVO();
        data.setSettlementName(entity.getSettlementName()); // 结算方
        data.setAmount(entity.getAmount()); // 付款金额
        data.setPayWayName(SettlementTypeEnum.getName(entity.getPayWay())); // 支付方式名称
        data.setSettlementTime(DateUtil.format(new Date(entity.getSettlementDate()), DatePattern.NORM_DATETIME_PATTERN)); // 支付时间
        data.setStatus(SettlementStatusEnum.getMessage(entity.getStatus())); // 支付状态
        return Wrapper.success(data);
    }

    @Override
    public Wrapper<List<PlatformSettlementTypeVO>> findSettlementType() {
        return feignService.findSettlementType();
    }

    @Override
    public Wrapper<List<MemberSettleChannelVO>> findSettlementChannel(UserLoginCacheDTO sysUser) {
        MemberSettleChannelQueryVO request = new MemberSettleChannelQueryVO();
        request.setPayType(OrderPayTypeEnum.ALLIN_PAY.getCode());
        request.setMemberId(sysUser.getMemberId());
        request.setRoleId(sysUser.getMemberRoleId());
        return feignService.findSettlementChannel(request);
    }

    @Override
    public Wrapper<PlatformSettlementAllInPayVO> getPlatformSettlementByDetailPaymentId(Long paymentId) {
        Specification<PlatformSettlementDetailDO> spec = (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("paymentId").as(Long.class), paymentId);
        List<PlatformSettlementDetailDO> details = detailRepository.findAll(spec);
        if (CollectionUtils.isEmpty(details)) {
            return Wrapper.fail(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        Long settlementId = details.stream().findFirst().map(PlatformSettlementDetailDO::getSettlementId).orElse(null);
        if (settlementId == null) {
            return Wrapper.fail(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        PlatformSettlementDO platformSettlementDO = repository.getOne(settlementId);
        if (!platformSettlementDO.getStatus().equals(SettlementStatusEnum.COMPLETE.getCode())) {
            return Wrapper.fail(ResponseCode.SA_PLATFORM_SETTLEMENT_NOT_EXIST);
        }
        PlatformSettlementAllInPayVO data = new PlatformSettlementAllInPayVO();
        data.setTradeNo(platformSettlementDO.getTradeNo());
        return Wrapper.success(data);
    }

    @Override
    public void payableExport(UserLoginCacheDTO sysUser, HttpServletResponse response, PlatformSettlementDetailPageVO queryParameter) {
        exportCommon(sysUser, response, queryParameter, false);

    }

    @Override
    public void receivableExport(UserLoginCacheDTO sysUser, HttpServletResponse response, PlatformSettlementDetailPageVO queryParameter) {
        exportCommon(sysUser, response, queryParameter, true);

    }

    /**
     * 通用导出功能
     * @param sysUser 登录用户
     * @param response 响应
     * @param queryParameter 查询条件
     * @param isSettlement 是否结算
     */
    private void exportCommon(UserLoginCacheDTO sysUser, HttpServletResponse response, PlatformSettlementDetailPageVO queryParameter, boolean isSettlement) {
        // step 1: 组装查询条件
        Specification<PlatformSettlementDetailDO> spec = buildDetailSpecification(sysUser, queryParameter, isSettlement);
        // step 2: 获取结算明细数据
        List<PlatformSettlementDetailDO> resultList = detailRepository.findAll(spec);
        // step 3: 设置导出模板数据
        List<Map<String, Object>> rows = resultList.stream().map(item -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put(PlatformSettlementExcelEnum.ORDER_NO.getMessage(), item.getOrderNo());
            map.put(PlatformSettlementExcelEnum.ORDER_ABSTRACT.getMessage(), item.getOrderAbstract());
            map.put(PlatformSettlementExcelEnum.SETTLEMENT_ORDER_TYPE.getMessage(), SettlementOrderTypeEnum.getMessage(item.getSettlementOrderType(), ""));
            map.put(PlatformSettlementExcelEnum.ORDER_TIME.getMessage(),  OrderDateTimeUtil.timestampToDateTimeString(item.getOrderTime()));
            map.put(PlatformSettlementExcelEnum.ORDER_TYPE.getMessage(), ReceiptInvoiceOrderTypeEnum.getMessage(item.getOrderType()));
            map.put(PlatformSettlementExcelEnum.IS_HAS_TAX.getMessage(), CommonBooleanEnum.getMessage(item.getIsHasTax()));
            map.put(PlatformSettlementExcelEnum.TAX_RATE.getMessage(), BigDecimal.valueOf(item.getTaxRate()).setScale(2, RoundingMode.HALF_UP) + "%");
            map.put(PlatformSettlementExcelEnum.ORDER_AMOUNT.getMessage(), BigDecimal.valueOf(item.getOrderAmount()).setScale(2, RoundingMode.HALF_UP));
            map.put(PlatformSettlementExcelEnum.COLLECT_AMOUNT.getMessage(), BigDecimal.valueOf(item.getCollectAmount()).setScale(2, RoundingMode.HALF_UP));
            map.put(PlatformSettlementExcelEnum.PAY_TIME.getMessage(), DateUtil.format(DateUtil.date(item.getPayTime()), "yyyy-MM-dd HH:mm"));
            map.put(PlatformSettlementExcelEnum.RATIO.getMessage(), BigDecimal.valueOf(item.getRatio()).setScale(2, RoundingMode.HALF_UP) + "%");
            map.put(PlatformSettlementExcelEnum.BROKERAGE.getMessage(), BigDecimal.valueOf(item.getBrokerage()).negate().setScale(2, RoundingMode.HALF_UP));
            map.put(PlatformSettlementExcelEnum.SETTLEMENT_AMOUNT.getMessage(), BigDecimal.valueOf(item.getSettlementAmount()).setScale(2, RoundingMode.HALF_UP));
            return map;
        }).collect(Collectors.toList());
        // 获取excel写入器，默认写出到第一个sheet
        ExcelWriter writer = ExcelUtil.getBigWriter();
        // 获取头部样式，获取样式后可自定义样式
        CellStyle style = writer.getHeadCellStyle();
        // 设置文本是否应换行。 将此标志设置为true通过在多行上显示单元格中的所有内容来使所有内容可见
        style.setWrapText(false);
        // 写入数据
        writer.write(rows);
        String fileName = PlatformSettlementExcelEnum.FILE_NAME.getMessage().concat("-") + DateUtil.date() + ".xls";
        // 写入响应
        try (ServletOutputStream out = response.getOutputStream()) {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            writer.flush(out, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
    }

    /**
     * 构建查询条件
     * @param sysUser 登录用户
     * @param queryParameter 查询条件
     * @param isSettlement 是否结算
     * @return 查询条件
     */
    private Specification<PlatformSettlementDetailDO> buildDetailSpecification(UserLoginCacheDTO sysUser, PlatformSettlementDetailPageVO queryParameter, boolean isSettlement) {
        return (root, query, builder) -> {
            Predicate settlementId = builder.equal(root.get("settlementId").as(Long.class), queryParameter.getSettlementId());
            query.where(settlementId);
            if (!isSettlement) {
                Predicate memberId = builder.equal(root.get("memberId").as(Long.class), sysUser.getMemberId());
                query.where(memberId);

            }
            if (StringUtils.hasLength(queryParameter.getOrderStartTime())) {
                Predicate orderTime = builder.greaterThanOrEqualTo(root.get("orderTime").as(Long.class), DateUtil.parse(queryParameter.getOrderStartTime()).getTime());
                query.where(orderTime);
            }
            if (StringUtils.hasLength(queryParameter.getOrderEndTime())) {
                Predicate orderTime = builder.lessThanOrEqualTo(root.get("orderTime").as(Long.class), DateUtil.endOfDay(DateUtil.parse(queryParameter.getOrderEndTime())).getTime());
                query.where(orderTime);
            }
            if (StringUtils.hasLength(queryParameter.getPayStartTime())) {
                Predicate payTime = builder.greaterThanOrEqualTo(root.get("payTime").as(Long.class), DateUtil.parse(queryParameter.getPayStartTime()).getTime());
                query.where(payTime);
            }
            if (StringUtils.hasLength(queryParameter.getPayEndTime())) {
                Predicate payTime = builder.lessThanOrEqualTo(root.get("payTime").as(Long.class), DateUtil.endOfDay(DateUtil.parse(queryParameter.getPayEndTime())).getTime());
                query.where(payTime);
            }
            if (StringUtils.hasLength(queryParameter.getOrderNo())) {
                Predicate orderNo = builder.like(root.get("orderNo").as(String.class), "%" + queryParameter.getOrderNo().trim() + "%");
                query.where(orderNo);
            }
            if (StringUtils.hasLength(queryParameter.getOrderAbstract())) {
                Predicate orderAbstract = builder.like(root.get("orderAbstract").as(String.class), "%" + queryParameter.getOrderAbstract().trim() + "%");
                query.where(orderAbstract);
            }
            return query.getRestriction();
        };
    }
}
